from PyQt5.QtWidgets import *
from PyQt5.QtGui import*#界面常用组件
from PyQt5.QtCore import *
from PyQt5 import*
from MyButton import MyButton
from Chess import Chess
import  sys
import cgitb
import time
cgitb.enable(format="text")
class SinglePlayGame(QWidget):
    #自定义信号
    backSignal=pyqtSignal()
    whiteRunSignal=pyqtSignal([QPoint])

    posWhite=[]
    posBlack=[]

    chessArr=[]
    oldChessArr=[]

    #记录棋子的颜色
    colorTable=[[None for i in range(0,19)] for i in range(0,19)]

    #二维数组统计每个点的得分
    scoreTable=[[None for i in range(0,19)] for i in range(0,19)]

    isLabel=False

    def __init__(self,parent=None):
        super().__init__(parent)
        self.isBlack=True
        self.resize(760,650)
        self.setWindowTitle("人机对战")

        #设置背景图片
        p=QPalette(self.palette())      #调色板
        brush=QBrush(QImage("./source/游戏界面.png"))
        p.setBrush(QPalette.Background,brush)
        self.setPalette(p)
        #设置图标
        self.setWindowIcon(QIcon("./source/icon.ico"))
        #设置固定大小
        self.setFixedSize(760,650)
        #添加按钮
        self.button1=MyButton("./source/返回按钮_hover.png","./source/返回按钮_press.png","./source/返回按钮_normal.png",parent=self)
        self.button1.move(650,50)
        self.button2=MyButton("./source/开始按钮_hover.png","./source/开始按钮_press.png","./source/开始按钮_normal.png",parent=self)
        self.button2.move(650,200)
        self.button3=MyButton("./source/悔棋按钮_hover.png","./source/悔棋按钮_press.png","./source/悔棋按钮_normal.png",parent=self)
        self.button3.move(650,250)
        self.button4=MyButton("./source/认输按钮_hover.png","./source/认输按钮_press.png","./source/认输按钮_normal.png",parent=self)
        self.button4.move(650,300)

        #绑定返回按钮和发送返回信号
        self.button1.clicked.connect(self.goBack)
        #绑定开始按钮和重绘函数
        self.button2.clicked.connect(self.newPaint)
        #悔棋槽函数和信号绑定
        self.button3.clicked.connect(self.backChess)
        #认输按钮
        self.button4.clicked.connect(self.giveup)

        self.whiteRunSignal.connect(self.draw)

    def draw(self,QPoint):
        i=QPoint.x()
        j=QPoint.y()
        x=50+i*30
        y=50+j*30
        self.chess=Chess(self.isBlack,parent=self)
        self.chess.move(x-15,y-15)
        if x*19+y not in self.posWhite:
            self.posWhite.append(x*19+y)
            self.chessArr.append(self.chess)
            self.colorTable[i][j]="white"
            self.chess.show()
        if self.isWin("white"):
            print("白子赢了!")
            self.showWinPic("white")
            self.isBlack=True
            return
        self.isBlack=True


    #新界面重新开始
    def newPaint(self):
        #记录棋子的颜色
        self.colorTable=[[None for i in range(0,19)] for i in range(0,19)]
        #二维数组统计每个点的得分
        self.scoreTable=[[None for i in range(0,19)] for i in range(0,19)]

        if self.isLabel:
            self.labelWin.close()
        self.isBlack=True
        if self.isWin("black") or self.isWin("white"):
            self.labelWin.close()
        self.oldChessArr.clear()
        for i in self.chessArr:
            self.oldChessArr.append(i)
        self.posBlack.clear()
        self.posWhite.clear()
        self.chessArr.clear()
        if len(self.oldChessArr)!=0:
            for c in self.oldChessArr:
                c.hide()

    #悔棋
    def backChess(self):
        if self.isLabel:
            self.labelWin.close()
        if self.isWin("black") or self.isWin("white"):
            self.labelWin.close()
        self.oldChessArr.clear()
        for i in self.chessArr:
            self.oldChessArr.append(i)
        if len(self.posBlack)>len(self.posWhite):
            self.isBlack=False
        elif len(self.posBlack)<len(self.posWhite):
            self.isBlack=True
        #白子想悔棋
        if self.isBlack:
            if len(self.posWhite)!=0:
                index=self.posWhite[-1]
                i=int(int((index/19)-50)/30)
                j=int(int((index%19)-50)/30)
                self.colorTable[i][j]=None
                self.scoreTable[i][j]=None
                self.posWhite.pop()
            if len(self.chessArr)!=0:
                self.chessArr.pop()
            self.repaint()
            self.isBlack=False
        #黑子想悔棋
        else:
            if len(self.posBlack)!=0:
                index=self.posBlack[-1]
                i=int(int((index/19)-50)/30)
                j=int(int((index%19)-50)/30)
                self.colorTable[i][j]=None
                self.scoreTable[i][j]=None
                self.posBlack.pop()
            if len(self.chessArr)!=0:
                self.chessArr.pop()
            self.repaint()
            self.isBlack=True

    #重写重绘界面函数
    def repaint(self):
        if self.isLabel:
            self.labelWin.close()
        self.chessArr.clear()
        if len(self.oldChessArr)!=0:
            for c in self.oldChessArr:
                c.hide()
        for i in range(0,19):
            for j in range(0,19):
                _x=50+i*self.width
                _y=50+j*self.width
                if _x*19+_y in self.posBlack:
                    self.chess=Chess(True,parent=self)
                    self.chess.move(_x-15,_y-15)
                    self.chess.show()
                    self.chessArr.append(self.chess)
                if _x*19+_y in self.posWhite:
                    self.chess=Chess(False,parent=self)
                    self.chess.move(_x-15,_y-15)
                    self.chess.show()
                    self.chessArr.append(self.chess)

    #发送返回信号
    def goBack(self):
        self.backSignal.emit()

    def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):
        #self.update()
        self.chess=Chess(self.isBlack,parent=self)
        #左上角坐标50,50  右下角坐标590,590
        self.width=(590-50)/18 #每个格子大小30.0
        x=int(a0.x())
        y=int(a0.y())
        #黑子自己走
        if self.isBlack:
            if x>=35 and y>=35 and x<=605 and y<=605:
                for i in range(0,19):
                    for j in range(0,19):
                        _x=50+i*self.width
                        _y=50+j*self.width
                        if abs(x-_x)<=15 and abs(y-_y)<=15 and _x*19+_y not in self.posBlack and _x*19+_y not in self.posWhite and not self.isWin("black") and not self.isWin("white"):
                            if _x*19+_y not in self.posBlack:
                                self.chess.move(_x-15,_y-15)
                                self.chess.show()
                                #self.update()
                                self.posBlack.append(_x*19+_y)
                                self.chessArr.append(self.chess)
                                self.colorTable[i][j]="black"

                            if self.isWin("black"):
                                print("黑子赢了!")
                                self.showWinPic("black")
                                self.isBlack=False
                                return
                            self.isBlack=False

                            #self.whiteRunSignal.emit()
                            import threading
                            threading.Thread(target=self.getPos).start()

        print("黑子：",self.posBlack)
        print("白子：",self.posWhite)

    #统计该点为中心计算周围每个方向上的五个点的得分,返回得分最大位置的坐标元组
    def score(self,x,y):#x是横坐标
        i=0
        j=0
        old_x=x
        old_y=y
        #上边五个点
        for a in range(5):
            if y-30>=35:
                y-=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y
        #下边五个点
        for a in range(5):
            if y+30<=605:
                y+=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y
        #左边五个点
        for a in range(5):
            if x-30>=35:
                x-=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y
        #右边五个点
        for a in range(5):
            if x+30<=605:
                x+=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y
        #左斜上五个点
        for a in range(0,5):
            if x-30>=35 and y-30>=35:
                x-=30
                y-=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y
        #右斜上五个点
        for a in range(0,5):
            if x+30<=605 and y-30>=35:
                x+=30
                y-=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y
        #右斜下五个点
        for a in range(0,5):
            if x+30<=605 and y+30<=605:
                x+=30
                y+=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y
        #左斜下
        for a in range(0,5):
            if x-30>=35 and y+30<=605:
                x-=30
                y+=30
                i=int((x-50)/30)
                j=int((y-50)/30)
                self.scoreTable[i][j]=self.total_score(x,y)
        x=old_x
        y=old_y


    #计算该点四个方向的得分总和
    def total_score(self,x,y):
        total_score=0
        #y轴方向总得分
        s_y=[]
        score_y=0
        #该点的五个竖直元组
        if y-120>=35:

            s_y.append(self.getScore(self.num_chess(x,y-120,x,y,0)[0],self.num_chess(x,y-120,x,y,0)[1]))
        if y-90>=35 and y+30<=605:
            #t=self.num_chess(x,y-90,x,y+30,0)
            s_y.append(self.getScore(self.num_chess(x,y-90,x,y+30,0)[0],self.num_chess(x,y-90,x,y+30,0)[1]))
        if y-60>=35 and y+60<=605:
            #t=self.num_chess(x,y-60,x,y+60,0)
            s_y.append(self.getScore(self.num_chess(x,y-60,x,y+60,0)[0],self.num_chess(x,y-60,x,y+60,0)[1]))
        if y-30>=35 and y+90<=605:
            #t=self.num_chess(x,y-30,x,y+90,0)
            s_y.append(self.getScore(self.num_chess(x,y-30,x,y+90,0)[0],self.num_chess(x,y-30,x,y+90,0)[1]))
        if y+120<=605:
            #t=self.num_chess(x,y,x,y+120,0)
            s_y.append(self.getScore(self.num_chess(x,y,x,y+120,0)[0],self.num_chess(x,y,x,y+120,0)[1]))
        for s in s_y:
            score_y+=s
        total_score+=score_y

        #x轴方向总得分
        s_x=[]
        score_x=0
        #该点的五个水平元组
        if x-120>=35:
            #t=self.num_chess(x-120,y,x,y,1)
            s_x.append(self.getScore(self.num_chess(x-120,y,x,y,1)[0],self.num_chess(x-120,y,x,y,1)[1]))
        if x-90>=35 and x+30<=605:
            #t=self.num_chess(x-90,y,x+30,y,1)
            s_x.append(self.getScore(self.num_chess(x-90,y,x+30,y,1)[0],self.num_chess(x-90,y,x+30,y,1)[1]))
        if x-60>=35 and x+60<=605:
            #t=self.num_chess(x-60,y,x+60,y,1)
            s_x.append(self.getScore(self.num_chess(x-60,y,x+60,y,1)[0],self.num_chess(x-60,y,x+60,y,1)[1]))
        if x-30>=35 and x+90<=605:
            #t=self.num_chess(x-30,y,x+90,y,1)
            s_x.append(self.getScore(self.num_chess(x-30,y,x+90,y,1)[0],self.num_chess(x-30,y,x+90,y,1)[1]))
        if x+120<=605:
            #t=self.num_chess(x,y,x+120,y,1)
            s_x.append(self.getScore(self.num_chess(x,y,x+120,y,1)[0],self.num_chess(x,y,x+120,y,1)[1]))
        for s in s_x:
            score_x+=s
        total_score+=score_x

        #左斜方向总得分
        s_zx=[]
        score_zx=0
        #该点的五个左斜元组
        if x-120>=35 and y-120>=35:
            #t=self.num_chess(x-120,y-120,x,y,2)
            s_zx.append(self.getScore(self.num_chess(x-120,y-120,x,y,2)[0],self.num_chess(x-120,y-120,x,y,2)[1]))
        if x-90>=35 and y-90>=35 and x+30<=605 and y+30<=605:
            #t=self.num_chess(x-90,y-90,x+30,y+30,2)
            s_zx.append(self.getScore(self.num_chess(x-90,y-90,x+30,y+30,2)[0],self.num_chess(x-90,y-90,x+30,y+30,2)[1]))
        if x-60>=35 and y-60>=35 and x+60<=605 and y+60<=605:
            #t=self.num_chess(x-60,y-60,x+60,y+60,2)
            s_zx.append(self.getScore(self.num_chess(x-60,y-60,x+60,y+60,2)[0],self.num_chess(x-60,y-60,x+60,y+60,2)[1]))
        if x-30>=35 and y-30>=35 and x+90<=605 and y+90<=605:
            #t=self.num_chess(x-30,y-30,x+90,y+90,2)
            s_zx.append(self.getScore(self.num_chess(x-30,y-30,x+90,y+90,2)[0],self.num_chess(x-30,y-30,x+90,y+90,2)[1]))
        if x+120<=605 and y+120<=605:
            #t=self.num_chess(x,y,x+120,y+120,2)
            s_zx.append(self.getScore(self.num_chess(x,y,x+120,y+120,2)[0],self.num_chess(x,y,x+120,y+120,2)[1]))
        for s in s_zx:
            score_zx+=s
        total_score+=score_zx

        #右斜
        s_yx=[]
        score_yx=0
        #该点的五个右斜元组
        if x-120>=35 and y+120<=605:
            #t=self.num_chess(x-120,y+120,x,y,3)
            s_yx.append(self.getScore(self.num_chess(x-120,y+120,x,y,3)[0],self.num_chess(x-120,y+120,x,y,3)[1]))
        if x-90>=35 and y+90<=605 and x+30<=605 and y-30>=35:
            #t=self.num_chess(x-90,y+90,x+30,y-30,3)
            s_yx.append(self.getScore(self.num_chess(x-90,y+90,x+30,y-30,3)[0],self.num_chess(x-90,y+90,x+30,y-30,3)[1]))
        if x-60>=35 and y+60<=605 and x+60<=605 and y-60>=35:
            #t=self.num_chess(x-60,y+60,x+60,y-60,3)
            s_yx.append(self.getScore(self.num_chess(x-60,y+60,x+60,y-60,3)[0],self.num_chess(x-60,y+60,x+60,y-60,3)[1]))
        if x-30>=35 and y+30<=605 and x+90<=605 and y-90>=35:
            #t=self.num_chess(x-30,y+30,x+90,y-90,3)
            s_yx.append(self.getScore(self.num_chess(x-30,y+30,x+90,y-90,3)[0],self.num_chess(x-30,y+30,x+90,y-90,3)[1]))
        if x+120<=605 and y-120>=35:
            #t=self.num_chess(x,y,x+120,y-120,3)
            s_yx.append(self.getScore(self.num_chess(x,y,x+120,y-120,3)[0],self.num_chess(x,y,x+120,y-120,3)[1]))
        for s in s_yx:
            score_yx+=s
        total_score+=score_yx

        return total_score

    #统计五元组黑白子的个数(起始位置，终止位置，方向(0:y  1:x  2:左斜  3:右斜)
    def num_chess(self,x1,y1,x2,y2,s):
        num_b=0
        num_w=0
        #s=0:y轴
        if s==0:
            for y in range(y1,y2+30,30):
                i=int((x1-50)/30)
                j=int((y-50)/30)
                if self.colorTable[i][j]=="black":
                    num_b+=1
                if self.colorTable[i][j]=="white":
                    num_w+=1
            return num_b,num_w
        #x轴
        elif s==1:
            for x in range(x1,x2+30,30):
                i=int((x-50)/30)
                j=int((y1-50)/30)
                if self.colorTable[i][j]=="black":
                    num_b+=1
                if self.colorTable[i][j]=="white":
                    num_w+=1
            return num_b,num_w
        #左斜
        elif s==2:
            x=x1
            y=y1
            while x!=x2+30 and y!=y2+30:
                i=int((x-50)/30)
                j=int((y-50)/30)
                if self.colorTable[i][j]=="black":
                    num_b+=1
                if self.colorTable[i][j]=="white":
                    num_w+=1
                x+=30
                y+=30
            return num_b,num_w
        #右斜
        elif s==3:
            x=x1
            y=y1
            while x!=x2+30 and y!=y2-30:
                i=int((x-50)/30)
                j=int((y-50)/30)
                if self.colorTable[i][j]=="black":
                    num_b+=1
                if self.colorTable[i][j]=="white":
                    num_w+=1
                x+=30
                y-=30
            return num_b,num_w

    #根据五元组黑白子的数量给出得分
    def getScore(self,num_b,num_w):
        if num_b==0 and num_w==0:
            return 0
        elif num_b==1 and num_w==0:
            return 35
        elif num_b==2 and num_w==0:
            return 800
        elif num_b==3 and num_w==0:
            return 15000
        elif num_b==4 and num_w==0:
            return 800000
        elif num_b==0 and num_w==1:
            return 15
        elif num_b==0 and num_w==2:
            return 400
        elif num_b==0 and num_w==3:
            return 1800
        elif num_b==0 and num_w==4:
            return 100000
        elif num_b!=0 and num_w!=0:
            return 0
        else:
            return 0

#计算坐标
    def getPos(self):
        max_x=0
        max_y=0
        max_v=0
        i1=0
        i2=0
        self.chess=Chess(self.isBlack,parent=self)
        # 遍历棋盘
        for i in range(0,19):
            for j in range(0,19):
                _x=50+i*30
                _y=50+j*30
                self.score(_x,_y)
        #找到得分最高的最优位置
        for i in range(0,19):
            for j in range(0,19):
                if self.scoreTable[i][j]!=None:
                    if self.scoreTable[i][j]>max_v and (50+i*30)*19+50+j*30 not in self.posBlack and (50+i*30)*19+50+j*30 not in self.posWhite:
                        max_v=self.scoreTable[i][j]
                        i1=i
                        j1=j
        point=QPoint(i1,j1)
        self.whiteRunSignal.emit(point)

#人机走路
    def machineChess(self):

        #time.sleep(1)
        print("轮到电脑走。。。。。")
        max_x=0
        max_y=0
        max_v=0
        i1=0
        i2=0
        self.chess=Chess(self.isBlack,parent=self)
        # 遍历棋盘
        for i in range(0,19):
            for j in range(0,19):
                _x=50+i*30
                _y=50+j*30
                self.score(_x,_y)
        #找到得分最高的最优位置
        for i in range(0,19):
            for j in range(0,19):
                if self.scoreTable[i][j]!=None:
                    if self.scoreTable[i][j]>max_v and (50+i*30)*19+50+j*30 not in self.posBlack and (50+i*30)*19+50+j*30 not in self.posWhite:
                        max_v=self.scoreTable[i][j]
                        max_x=50+i*30
                        max_y=50+j*30
                        i1=i
                        j1=j
        print("最大评分的坐标：%d,%d" %(i1,j1))
        self.chess.move(max_x-15,max_y-15)
        if max_x*19+max_y not in self.posWhite:
            self.posWhite.append(max_x*19+max_y)
            self.chessArr.append(self.chess)
            self.colorTable[i1][j1]="white"
            self.chess.show()
        if self.isWin("white"):
            print("白子赢了!")
            self.showWinPic("white")
            self.isBlack=True
            return
        self.isBlack=True



    #胜利显示图片
    def showWinPic(self,color):
        if color=="black":
            self.pixmapWin=QPixmap("./source/黑棋胜利.png")
            self.labelWin=QLabel(parent=self)
            self.labelWin.setPixmap(self.pixmapWin)
            self.labelWin.setFixedSize(self.pixmapWin.size())
            self.labelWin.show()
            self.labelWin.move(50,50)
        else:
            self.pixmapWin=QPixmap("./source/白棋胜利.png")
            self.labelWin=QLabel(parent=self)
            self.labelWin.setPixmap(self.pixmapWin)
            self.labelWin.setFixedSize(self.pixmapWin.size())
            self.labelWin.show()
            self.labelWin.move(50,50)
        self.isLabel=True

    #自己认输显示图片
    def giveup(self):
        if self.isWin("black") or self.isWin("white"):
            self.labelWin.close()
        #黑子认输
        if self.isBlack:
            self.pixmapWin=QPixmap("./source/白棋胜利.png")
            self.labelWin=QLabel(parent=self)
            self.labelWin.setPixmap(self.pixmapWin)
            self.labelWin.setFixedSize(self.pixmapWin.size())
            self.labelWin.show()
            self.labelWin.move(50,50)

        #白子认输
        else:
            self.pixmapWin=QPixmap("./source/黑棋胜利.png")
            self.labelWin=QLabel(parent=self)
            self.labelWin.setPixmap(self.pixmapWin)
            self.labelWin.setFixedSize(self.pixmapWin.size())
            self.labelWin.show()
            self.labelWin.move(50,50)
        self.isLabel=True

    #判断输赢
    def isWin(self,color):
        if color=="black":
            #判断每行是否有五黑子连在一起
            for i in range(0,15):
                for j in range(0,19):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posBlack and (_x+30)*19+_y in self.posBlack and (_x+60)*19+_y in self.posBlack and (_x+90)*19+_y in self.posBlack and (_x+120)*19+_y in self.posBlack:
                        return True
            #判断列
            for j in range(0,15):
                for i in range(0,19):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posBlack and _x*19+30+_y in self.posBlack and _x*19+_y+60 in self.posBlack and _x*19+_y+90 in self.posBlack and _x*19+_y+120 in self.posBlack:
                        return True
            #判断左斜
            for i in range(0,15):
                for j in range(0,15):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posBlack and (_x+30)*19+30+_y in self.posBlack and (_x+60)*19+_y+60 in self.posBlack and (_x+90)*19+_y+90 in self.posBlack and (_x+120)*19+_y+120 in self.posBlack:
                        return True
            #判断右斜
            for i in range(0,15):
                for j in range(0,19):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posBlack and (_x+30)*19-30+_y in self.posBlack and (_x+60)*19+_y-60 in self.posBlack and (_x+90)*19+_y-90 in self.posBlack and (_x+120)*19+_y-120 in self.posBlack:
                        return True
            return False
        else:
            #判断每行是否有五白子连在一起
            for i in range(0,15):
                for j in range(0,19):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posWhite and (_x+30)*19+_y in self.posWhite and (_x+60)*19+_y in self.posWhite and (_x+90)*19+_y in self.posWhite and (_x+120)*19+_y in self.posWhite:
                        return True
            #判断列
            for j in range(0,15):
                for i in range(0,19):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posWhite and _x*19+30+_y in self.posWhite and _x*19+_y+60 in self.posWhite and _x*19+_y+90 in self.posWhite and _x*19+_y+120 in self.posWhite:
                        return True
            #判断左斜
            for i in range(0,15):
                for j in range(0,15):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posWhite and (_x+30)*19+30+_y in self.posWhite and (_x+60)*19+_y+60 in self.posWhite and (_x+90)*19+_y+90 in self.posWhite and (_x+120)*19+_y+120 in self.posWhite:
                        return True
            #判断右斜
            for i in range(0,15):
                for j in range(0,19):
                    _x=50+i*self.width
                    _y=50+j*self.width
                    if _x*19+_y in self.posWhite and (_x+30)*19-30+_y in self.posWhite and (_x+60)*19+_y-60 in self.posWhite and (_x+90)*19+_y-90 in self.posWhite and (_x+120)*19+_y-120 in self.posWhite:
                        return True
            return False

# if __name__=="__main__":
#     a=QApplication(sys.argv)
#     m=SinglePlayGame()
#     m.show()
#     sys.exit(a.exec_())